package com.li.toolkit.utils;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @author LiDong
 * @version 1.0.0
 * @createTime 2/19/2022 10:12 AM
 */
public final class FtpUtils {

    private static final Logger logger = LoggerFactory.getLogger(FtpUtils.class);

    private FtpUtils() {
    }

    /**
     * @param ftpUrl      ftp 主机地址
     * @param ftpUserName 用户名
     * @param ftpPassword 密码
     * @param port        端口号
     * @return FTPClient
     */
    public static FTPClient getFtpClient(String ftpUrl, String ftpUserName, String ftpPassword, int port) throws IOException {
        FTPClient ftpClient = new FTPClient();
        // 获取连接
        ftpClient.connect(ftpUrl, port);
        // 登录
        ftpClient.login(ftpUserName, ftpPassword);
        int reply = ftpClient.getReplyCode();
        if (FTPReply.isPositiveCompletion(reply)) {
            logger.info("成功登录 ftp 服务器...");

        } else {
            logger.info("登录服务器,被动模式主机：[{}:{}]", ftpClient.getPassiveHost(), ftpClient.getPassivePort());
            logger.info("登录服务器,主动模式主机：[{}:{}]", ftpClient.getRemoteAddress(), ftpClient.getRemotePort());
            logger.info("登录服务器,本地主机：[{}:{}]", ftpClient.getLocalAddress(), ftpClient.getLocalPort());
            logger.info("登录服务器,返回代码：[{}], 显示状态[{}]", ftpClient.getReplyCode(), ftpClient.getStatus());
            ftpClient.disconnect();
        }
        return ftpClient;
    }

    /**
     * @param ftpUrl      ftp 主机地址
     * @param ftpUserName 用户名
     * @param ftpPassword 密码
     * @param port        端口号
     * @return FTPSClient
     */
    public static FTPSClient getFtpsClient(String ftpUrl, String ftpUserName, String ftpPassword, int port) throws IOException {
        FTPSClient ftpsClient = new FTPSClient("SSL", true);
        // 获取连接
        ftpsClient.connect(ftpUrl, port);
        // 登录
        ftpsClient.login(ftpUserName, ftpPassword);
        int reply = ftpsClient.getReplyCode();
        if (FTPReply.isPositiveCompletion(reply)) {
            logger.info("成功登录 ftp 服务器...");
        } else {
            logger.info("登录服务器,被动模式主机：[{}:{}]", ftpsClient.getPassiveHost(), ftpsClient.getPassivePort());
            logger.info("成功登录服务器,主动模式主机：[{}:{}]", ftpsClient.getRemoteAddress(), ftpsClient.getRemotePort());
            logger.info("成功登录服务器,本地主机：[{}:{}]", ftpsClient.getLocalAddress(), ftpsClient.getLocalPort());
            logger.info("成功登录服务器,返回代码：[{}], 显示状态[{}]", ftpsClient.getReplyCode(), ftpsClient.getStatus());
            ftpsClient.disconnect();
        }
        return ftpsClient;
    }


    /**
     * 获得 Ftp 上文件的流
     *
     * @param ftpClient        ftp 连接对象
     * @param ftpPathDirectory ftp 上文件目录
     * @param fileName         文件名称
     * @return InputStream
     * @throws IOException
     */
    public static InputStream getFtpInputStream(FTPClient ftpClient, String ftpPathDirectory, String fileName) throws IOException {
        InputStream inputStream = null;
        boolean changeFlag = !ftpClient.changeWorkingDirectory(ftpPathDirectory);
        if (changeFlag) {
            throw new IllegalArgumentException("当前文件夹不存在!");
        }
        /**
         * 主动模式传送数据时是“服务器”连接到“客户端”的端口；被动模式传送数据是“客户端”连接到“服务器”的端口
         * 主动模式需要客户端必须开放端口给服务器，很多客户端都是在防火墙内，开放端口给FTP服务器访问比较困难。
         * 被动模式只需要服务器端开放端口给客户端连接就行了。
         */
        // 被动模式
        ftpClient.enterLocalPassiveMode();
        try {
            inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        } catch (IOException e) {
            logger.error("IOException Error Occur{}:", e.getMessage(), e);
        } catch (Exception e) {
            logger.error("Error Occur{}:", e.getMessage(), e);
        }
        if (null == inputStream) {
            // 主动模式
            ftpClient.enterLocalActiveMode();
            inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        }
        Objects.requireNonNull(inputStream);
        return inputStream;
    }

    /**
     * 下载 ftp 文件
     *
     * @param ftpClient     ftpClient
     * @param pathDirectory ftp 文件目录
     * @param fileName      ftp 文件名称
     * @param downLoadPath  下载路径
     * @return String
     * @throws IOException
     */
    public static String downLoadFtpFile(FTPClient ftpClient, String pathDirectory, String fileName, String downLoadPath) throws IOException {
        boolean changeFlag = !ftpClient.changeWorkingDirectory(pathDirectory);
        if (changeFlag) {
            throw new IllegalArgumentException("当前文件目录不存在！");
        }
        // 文件绝对路径
        String fileFullPath = downLoadPath + fileName;
        File file = new File(fileFullPath);
        OutputStream outputStream = new FileOutputStream(file);
        for (FTPFile ftpFile : ftpClient.listFiles()) {
            String ftpFileName = ftpFile.getName();
            logger.info("目录：{} 下有文件：{}", pathDirectory, ftpFileName);
            if (ftpFileName.contains(fileName)) {
                ftpClient.retrieveFile(ftpFileName, outputStream);
                outputStream.close();
            }
        }
        return "下载成功，下载的文件路径为：" + fileFullPath;
    }

    /**
     * 文件上传
     *
     * @param ftpClient     ftpClient
     * @param ftpUploadPath 文件上传 ftp 目录
     * @param fileFullPath  本地文件 绝对路径
     * @return String
     * @throws IOException
     */
    public static String uploadFtpFile(FTPClient ftpClient, String ftpUploadPath, String fileFullPath) throws IOException {
        boolean changeFlag = !ftpClient.changeWorkingDirectory(ftpUploadPath);
        if (changeFlag) {
            ftpClient.makeDirectory(ftpUploadPath);
            logger.info("在 ftp 下创建文件夹：{}", ftpUploadPath);
        }
        ftpClient.changeWorkingDirectory(ftpUploadPath);
        File file = new File(fileFullPath);
        InputStream inputStream = new FileInputStream(file);
        ftpClient.storeFile(file.getName(), inputStream);
        return "上传成功，上传的文件路径为：" + ftpUploadPath + file.getName();
    }


    /**
     * 列出指定目录下的文件
     *
     * @param ftpClient         ftpClient
     * @param filePathDirectory 目录地址
     * @return FTPFile[]
     */
    public static FTPFile[] listFtpFiles(FTPClient ftpClient, String filePathDirectory) throws IOException {
        boolean changeFlag = !ftpClient.changeWorkingDirectory(filePathDirectory);
        if (changeFlag) {
            throw new IllegalArgumentException("当前目录不存在！");
        }
        return ftpClient.listFiles();
    }

}

